package com.cgrs572.shortlink.admin.common.biz.user;

import cn.hutool.core.util.StrUtil;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;

/**
 * 用户信息传输过滤器
 */
@RequiredArgsConstructor
public class UserTransmitFilter implements Filter {
    /**
     * 注意：SpringMvc的全局异常拦截器无法拦截到过滤器抛出的异常，原因如下：
     * 过滤器拦截到的请求是在进入SpringMvc之前的，而异常拦截器是基于SpringMvc的，它只会处理SpringMvc控制器方法所抛出的异常
     * 在经过网关的自定义路由过滤器后才会到达该过滤器
     * 整个过程：即前端传来请求会先经网关路由过滤器，然后判断是否是指定的白名单uri，若是则直接放行进入到后管服务过滤器中；若不是则
     *          此时就需要通过用户的用户名和Token以及缓存来判断是否已登录，若已登录则向请求头中添加用户id和用户真是姓名并放行；若用户名
     *          或Token或缓存出错则代表登录信息错误，此时构建构建好的错误响应并返回给前端，前端收到响应后会自行处理
     */
    @Override
    @SneakyThrows // 作用：忽略异常
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain){
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        String username = httpServletRequest.getHeader("username");
        if (StrUtil.isNotBlank(username)) {
            // 将用户信息存储到应用上下文
            String userId = httpServletRequest.getHeader("userId");
            String realName = httpServletRequest.getHeader("realName");
            UserInfoDTO userInfoDTO = new UserInfoDTO(userId, username, realName);
            UserContext.setUser(userInfoDTO);
        }
        try {
            // 过滤器放行
            filterChain.doFilter(servletRequest, servletResponse);
        } finally {
            // 执行完放行后的逻辑后，最后返回过滤器删除用户在上下文中的信息
            UserContext.removeUser();
        }
    }
}